package de.joergviola.mobj.client.storage;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.rpc.AsyncCallback;

import de.joergviola.mobj.shared.EntityReader;
import de.joergviola.mobj.shared.ObjectNotFoundException;
import de.joergviola.mobj.shared.Persistable;
import de.joergviola.mobj.shared.UnknownEntityException;

public class JSONEntityReader implements EntityReader {

	private final JSONObject json;
	private final StorageTransaction tx;

	interface JSONValueVisitor {
		void visit(JSONValue value);
	}

	public JSONEntityReader(StorageTransaction tx, JSONObject json) {
		this.tx = tx;
		this.json = json;
	}

	@Override
	public String readString(String name) {
		JSONString s = (JSONString) json.get(name);
		if (s == null)
			return null;
		return s.stringValue();
	}

	@Override
	public Long readLong(String name) {
		JSONNumber n = (JSONNumber) json.get(name);
		if (n == null)
			return null;
		return new Long((long) n.doubleValue());
	}

	@Override
	public Double readDouble(String name) {
		JSONNumber n = (JSONNumber) json.get(name);
		if (n == null)
			return null;
		return new Double(n.doubleValue());
	}

	@Override
	public Date readDate(String name) {
		JSONNumber n = (JSONNumber) json.get(name);
		if (n == null)
			return null;
		return new Date((long) n.doubleValue());
	}

	@Override
	public List<Long> readListLong(String name) {
		JSONValue jsonValue = json.get(name);
		if (jsonValue == null)
			return null;
		ArrayList<Long> result = new ArrayList<Long>();
		JSONArray array = jsonValue.isArray();
		for (int i = 0; i < array.size(); i++) {
			JSONValue value = array.get(i);
			JSONNumber number = value.isNumber();
			result.add(new Long((long) number.doubleValue()));
		}
		return result;
	}

	@Override
	public List<String> readListString(String name) {
		JSONValue jsonValue = json.get(name);
		if (jsonValue == null)
			return null;
		ArrayList<String> result = new ArrayList<String>();
		JSONArray array = jsonValue.isArray();
		for (int i = 0; i < array.size(); i++) {
			JSONValue value = array.get(i);
			JSONString s = value.isString();
			result.add(s.stringValue());
		}
		return result;
	}

	@Override
	public String[] readStringArray(String name) {
		JSONValue jsonValue = json.get(name);
		if (jsonValue == null)
			return null;
		JSONArray array = jsonValue.isArray();
		String[] result = new String[array.size()];
		for (int i = 0; i < array.size(); i++) {
			JSONValue value = array.get(i);
			result[i] = value.isString().stringValue();
		}
		return result;
	}

	@Override
	public <T extends Persistable> void readPersistable(String name,
			Class<T> clazz, AsyncCallback<T> setter)
			throws ObjectNotFoundException, UnknownEntityException {
		JSONNumber n = (JSONNumber) json.get(name);
		if (n == null) {
			setter.onSuccess(null);
			return;
		}
		Long id = new Long((long) n.doubleValue());
		tx.get(clazz.getName(), id, setter);
	}
}